#include <iostream>
#include <functional>
#include <unistd.h>
#include <memory>
#include <cstdint>
#include <vector>
#include <unordered_map>

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;
class TimerTask
{
private:
    uint64_t _id; // 定时器的id
    uint32_t _timeout; //定时任务的超时时间
    bool _canceled; // 定时任务是否被取消
    TaskFunc _task_cb; // 定时器对象要执行的定时任务
    ReleaseFunc _release; //用于删除TimerWheel中保存的定时器对象信息

public:
    TimerTask(uint64_t id,uint32_t timeout, const TaskFunc& cb)
        :_id(id)
        ,_timeout(timeout)
        ,_task_cb(cb)
        ,_canceled(false)
    {}

    ~TimerTask()
    {
        if(_canceled == false) _task_cb();
        _release();
    }

    void Cancel()
    {
        _canceled = true;
    }

    void SetRelease(const ReleaseFunc& cb)
    {
        _release = cb;
    }

    uint32_t DelayTime()
    {
        return _timeout;
    }
};

class TimerWheel
{
private:
    using WeakTask = std::weak_ptr<TimerTask>;
    using PtrTask = std::shared_ptr<TimerTask>;

    int _tick; //当前的秒针，秒针走到哪，就释放哪，执行哪的任务
    int _capacity; // 时间轮的最大容量，也就是最大延迟时间

    std::vector<std::vector<PtrTask>> _wheel; // 时间轮，一个二维数组
    std::unordered_map<uint64_t,WeakTask> _timers; // id to Weaktask

    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it != _timers.end())
        {
            _timers.erase(it);
        }   
    }

public:
    TimerWheel()
        :_capacity(60)
        ,_tick(0)
        ,_wheel(_capacity)
    {}

    //添加时间任务
    void TimerAdd(uint64_t id,uint32_t timeout,const TaskFunc& cb)
    {
        PtrTask ptr(new TimerTask(id,timeout,cb));
        ptr->SetRelease(std::bind(&TimerWheel::RemoveTimer,this,id));
        int pos = (_tick + timeout) % _capacity; // 找到需要存放的位置
        _wheel[pos].push_back(ptr);
        _timers[id] = WeakTask(ptr);
    }

    //刷新某定时任务
    void TimerRefresh(uint64_t id)
    {
        //通过timers中的WeakTask构造一个shareed_ptr出来，添加到轮子的新位置中
        auto it = _timers.find(id);
        if(it == _timers.end())
        {
            return;
        }

        PtrTask ptr = it->second.lock();
        int timeout = ptr->DelayTime();
        int pos = (_tick + timeout) % _capacity;
        _wheel[pos].push_back(ptr);
    }

    //取消某定时任务
    void TimerCancel(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it == _timers.end())
        {
            return;
        }

        PtrTask ptr = it->second.lock();
        if(ptr) ptr->Cancel();
    }

    //秒针往后走一部，这个函数应该每秒执行一次;
    void RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear(); // 清空指定位置的数组,就把在该位置的所有shared_ptr全部释放掉了
    }
};

class Test
{
public:
    Test()
    {
        std::cout << "构造" << std::endl;
    }
    ~Test()
    {
        std::cout << "析构" << std::endl;
    }
};

void DelTest(Test* t)
{
    delete t;
}

int main()
{
    TimerWheel tw;

    Test* t = new Test();

    tw.TimerAdd(888,5,std::bind(DelTest,t));

    for(int i = 0;i < 5;i++)
    {
        sleep(1);
        tw.TimerRefresh(888);//刷新任务
        tw.RunTimerTask();//秒针向后走
        std::cout << "刷新了一下定时任务，5秒钟后销毁！" << std::endl;
    }

    while(true)
    {
        sleep(1);
        std::cout << "---------------------------" << std::endl;
        tw.RunTimerTask();//秒针往后走，但不刷新任务
    }

    return 0;
}